#include "STEClasses.h"
#include "Value.h"
#include "ParserUtil.h"

// Global Entry
void GlobalEntry::print(ostream& os, int indent) const {
	prtln(os,indent+STEP_INDENT);
	if (symTab()) {
		SymTab::const_iterator it = symTab()->begin();
		for (;it!=symTab()->end();++it) {
			if ((*it) && (*it)->name() != "any") {
				(*it)->print(os,indent+STEP_INDENT);
			}
		}
	}
	// Rules
	vector<RuleNode*>::const_iterator it = rules_.begin();
	for (;it!=rules_.end();++it) {
		if ((*it)) 
			(*it)->print(os,indent+STEP_INDENT);
	}
	prtln(os,indent);
	prtln(os,indent);
}
// BlockEntry
void BlockEntry::print(ostream& out, int indent) const {
	// TODO
}

// Variable Entry
void VariableEntry::print(ostream& os, int indent) const {
	string typeName = type()->name();
	if (type()->tag()==Type::CLASS) {
		typeName += " " + type()->typeDesc()->name();
	}
	if (initVal()) {
		os << typeName << " " << name() << " = ";
		initVal()->print(os,indent);
		os << ";";
	}
	else
		os << typeName << " " << name() << ";";
	prtln(os, indent);
}

// ClassEntry
void ClassEntry::print(ostream& out, int indent) const {
	out << "class " << name() << ";";
	prtln(out, indent);
}

// FunctionEntry
void FunctionEntry::print(ostream& out, int indent) const {

	const Type* retT = type()->retType();
	retT->print(out,indent);
	out << " " << name() << "(";
	// Parameters 
	string params;
	if (symTab()) {
		SymTab::const_iterator it = symTab()->begin();
		for (;it!=symTab()->end();++it) {
			if ( (*it) && (*it)->kind() == SymTabEntry::VARIABLE_KIND) {
				VariableEntry* var = (VariableEntry*)(*it);
				if (var->varKind() == VariableEntry::PARAM_VAR) {
					if (params.empty()) params += var->type()->fullName() + " " + var->name();
					else params += ", " + var->type()->fullName()+ " " + var->name();
				}
			}
		}
	}
	out << params << ")";
	bool declExist = false;
	if (symTab()) {
		SymTab::const_iterator it = symTab()->begin();
		for (;it!=symTab()->end();++it) {
			if ( (*it) && (*it)->kind() == SymTabEntry::VARIABLE_KIND) {
				VariableEntry* var = (VariableEntry*)(*it);
				if (var->varKind() != VariableEntry::PARAM_VAR) {
					declExist = true;
					break;
				}
			}
		}
	}
	if (declExist || body()) {
		out << " {";
		prtln(out,indent + STEP_INDENT);

		SymTab::const_iterator it = symTab()->begin();
		for (;it!=symTab()->end();++it) {
			if ( (*it) &&  (*it)->kind() == SymTabEntry::VARIABLE_KIND) {
				VariableEntry* var = (VariableEntry*)(*it);
				if (var->varKind() != VariableEntry::PARAM_VAR) {
					out  << var->type()->name() << " " << var->name() << ";";
					prtln(out,indent + STEP_INDENT);
				}
			}
		}
		if (body()) {
			body()->printWithoutBraces(out,indent+STEP_INDENT);
		}
		out << "};";
		prtln(out,indent);
	} else {
		out << ";";
		prtln(out,indent);
	}
}

// EventEntry
void EventEntry::print(ostream& out, int indent) const {
	const Type* t = type();
	out << "event " << name();

	if (symTab() == NULL) {
		out << ";";prtln(out,indent);
		return;
	} else {
		out << "(";
	}
	SymTab::const_iterator it = symTab()->begin();
	for (;it!=symTab()->end();) {
		if ((*it)) {
			(*it)->type()->print(out,indent);
			out << " " << (*it)->name();
		}
		if ( (++it) != symTab()->end() )
			out << ", ";
	}
	out << ");";
	prtln(out,indent);
}
